import { WebMapTileServiceImageryProvider, Cartesian3, Rectangle, WebMercatorTilingScheme } from 'cesium';
import Tile from './Tile'
import Camera from './Camera'
// import tileShader from './Shader/tile.wgsl?raw'
import tileShader from '@/Render/Shader/tile.wgsl?raw';
let getLevel = (ratio: number) => {
    let levelRaios = [];
    for (let i = 0; i < 20; i++) {
        levelRaios.push(1 / Math.pow(2, i));
    }
    //判断ratio在哪两个数之间
    for (let i = 0; i < levelRaios.length - 1; i++) {
        if (ratio <= levelRaios[i] && ratio > levelRaios[i + 1]) {
            return i + 2;
        }
    }
}
export default class QuadtreePrimitive {
    private _tilesToRender: Tile[]
    private _camera: Camera
    device: GPUDevice;
    pipeline: GPURenderPipeline;
    constructor(camera: Camera) {
        this._camera = camera;
        // console.time('QuadtreePrimitive');
        let tile1 = new Tile(0, 0, 2);
        let tile2 = new Tile(1, 0, 2);
        let tile3 = new Tile(2, 0, 2);
        let tile4 = new Tile(3, 0, 2);
        let tile5 = new Tile(0, 1, 2);
        let tile6 = new Tile(1, 1, 2);
        let tile7 = new Tile(2, 1, 2);
        let tile8 = new Tile(3, 1, 2);
        // console.timeEnd('QuadtreePrimitive');

        let tile9 = new Tile(0, 2, 2);
        let tile10 = new Tile(1, 2, 2);
        let tile11 = new Tile(2, 2, 2);
        let tile12 = new Tile(3, 2, 2);
        let tile13 = new Tile(0, 3, 2);
        let tile14 = new Tile(1, 3, 2);
        let tile15 = new Tile(2, 3, 2);
        let tile16 = new Tile(3, 3, 2);
        this._tilesToRender = [];
        this._tilesToRender.push(tile1, tile2, tile3, tile4);
        this._tilesToRender.push(tile5, tile6, tile7, tile8);
        this._tilesToRender.push(tile9, tile10, tile11, tile12);
        this._tilesToRender.push(tile13, tile14, tile15, tile16);
        // let tile1 = new Tile(0, 0, 1);                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                               
        // let tile2 = new Tile(0, 1, 1);
        // let tile3 = new Tile(1, 0, 1);
        // let tile4 = new Tile(1, 1, 1);
        // this._tilesToRender = [];
        // this._tilesToRender.push(tile3, tile4);
        // this._tilesToRender.push(tile1, tile2);
        // this.selectTilesBylevel(2);
    }


    public get TilesToRender() {
        return this._tilesToRender
    }
    /**
     * @description: 根据视图范围来选择切片
     */

    public selectTilesToRender(viewExtent?: Rectangle) {
        const tilingScheme = new WebMercatorTilingScheme();
        this._tilesToRender = [];
        if (!viewExtent) {
            const numberOfXTiles = tilingScheme.getNumberOfXTilesAtLevel(2);
            const numberOfYTiles = tilingScheme.getNumberOfYTilesAtLevel(2);
            for (let x = 0; x < numberOfXTiles; x++) {
                for (let y = 0; y < numberOfYTiles; y++) {
                    this._tilesToRender.push(new Tile(x, y, 2));
                }
            }
            return;
        }
        const levelZeroTile = new Tile(0, 0, 0);
        let rectMercator = tilingScheme.rectangleToNativeRectangle(levelZeroTile.rectangle);
        let extentMercator = tilingScheme.rectangleToNativeRectangle(viewExtent);
        let width = extentMercator.width;

        let ratio = width / rectMercator.width;
        let westRatio = (extentMercator.west - rectMercator.west) / rectMercator.width;
        let eastRatio = (extentMercator.east - rectMercator.west) / rectMercator.width;
        if (width < 0) {
            width = extentMercator.east - extentMercator.west + rectMercator.width;
            ratio = width / rectMercator.width;
        }
        let northRatio = (rectMercator.north - extentMercator.north) / rectMercator.height;
        let southRatio = (rectMercator.north - extentMercator.south) / rectMercator.height;
        let level = getLevel(ratio);
        const numberOfXTiles = tilingScheme.getNumberOfXTilesAtLevel(level);
        const numberOfYTiles = tilingScheme.getNumberOfYTilesAtLevel(level);
        let startX = Math.floor(numberOfXTiles * westRatio);
        let endX = Math.floor(numberOfXTiles * eastRatio + 1);
        let startY = Math.floor(numberOfYTiles * northRatio);
        let endY = Math.floor(numberOfYTiles * southRatio + 1);
        if (extentMercator.width < 0) {
            // console.log(westRatio, eastRatio);
            // console.log(startX, endX,);
            for (let x = 0; x < endX + 1; x++) {
                for (let y = startY; y < endY; y++) {
                    this._tilesToRender.push(new Tile(x, y, level));
                }

            }
            for (let x = startX - 1; x < numberOfXTiles; x++) {
                for (let y = startY; y < endY; y++) {
                    this._tilesToRender.push(new Tile(x, y, level));
                }
            }

        }
        else {
            for (let x = startX; x < endX; x++) {
                for (let y = startY; y < endY; y++) {
                    this._tilesToRender.push(new Tile(x, y, level));
                }
            }
        }
        // console.log(this._tilesToRender);
    }
    createCommonds(device:GPUDevice) {
        this.device=device;
        const bindGroupLayout1 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.VERTEX, // 这些 uniform 变量在顶点着色器中使用
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false, // 假设这里不使用动态偏移量
                    },
                },
                {
                    binding: 1,
                    visibility: GPUShaderStage.VERTEX,
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false,
                    },
                },
                {
                    binding: 2,
                    visibility: GPUShaderStage.VERTEX,
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: false,
                    },
                },
                // 其他绑定项...
            ],
        });
        // 绑定组布局 0
        const bindGroupLayout0 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.FRAGMENT, // 采样器在片段着色器中使用
                    sampler: {
                        type: 'filtering',
                    },
                },
                {
                    binding: 1,
                    visibility: GPUShaderStage.FRAGMENT, // 纹理数组在片段着色器中使用
                    texture: {
                        sampleType: 'float',
                        viewDimension: '2d-array',
                    },
                },
            ],
        });

        // 绑定组布局 2 
        const bindGroupLayout2 = this.device.createBindGroupLayout({
            entries: [
                {
                    binding: 0,
                    visibility: GPUShaderStage.FRAGMENT, // 整数统一变量在片段着色器中使用
                    buffer: {
                        type: 'uniform',
                        hasDynamicOffset: true, // 假设这里不使用动态偏移量
                        // minBindingSize: 0, // 指定绑定大小为 4 字节
                    },
                },
            ],
        });
        //绑定组布局 (BindGroupLayout) 是对单个绑定组资源的描述，它决定了每个绑定组的资源布局。
        const pipelineLayout = this.device.createPipelineLayout({
            bindGroupLayouts: [bindGroupLayout0, bindGroupLayout1, bindGroupLayout2],
        });
        //初始化渲染管线
        this.pipeline = this.device.createRenderPipeline({
            layout: pipelineLayout,
            vertex: {
                module: this.device.createShaderModule({
                    code: tileShader
                }),
                buffers: [{
                    arrayStride: 3 * 4,
                    attributes: [{
                        format: 'float32x3',
                        offset: 0,
                        shaderLocation: 0
                    }]
                }, {
                    arrayStride: 2 * 4,
                    attributes: [{
                        format: 'float32x2',
                        offset: 0,
                        shaderLocation: 1
                    }]
                }],
                entryPoint: 'vs_main'
            },
            primitive: {
                topology: 'triangle-list', // try point-list, line-list, line-strip, triangle-strip?
                // 开启背面剔除
                cullMode: 'back',
            },
            fragment: {
                module: this.device.createShaderModule({
                    code: tileShader
                }),
                entryPoint: 'fs_main',
                targets: [
                    {
                        format: 'rgba8unorm'
                    }
                ]
            }
        });
    }


    sortTilesBydistance(cameraPosition: Cartesian3) {
        this._tilesToRender.sort((a, b) => {
            return a.distance(cameraPosition) - b.distance(cameraPosition)
        })
    }
}